﻿using System;
using System.IO;
using System.Threading.Tasks;
using Windows.ApplicationModel.Core;
using Windows.Storage;
using Windows.UI;
using Windows.UI.Core;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Media.Imaging;
using com.IronOne.BoardPACWinApp.Helpers;
using com.IronOne.BoardPACWinApp.Sync;
using com.IronOne.BoardPACWinApp.View.Page;
using com.IronOne.BoardPACWinApp.View.UserControl;
using com.IronOne.BoardPACWinApp.ViewModel;
using com.IronOne.BoardPACWinAppBO.Agenda;
using com.IronOne.BoardPACWinAppBO.General;
using com.IronOne.BoardPACWinAppBO.Paper;
using com.IronOne.BoardPACWinAppService.Auth;
using com.IronOne.BoardPACWinAppService.Comment;
using com.IronOne.BoardPACWinAppUtil.Enums;
using com.IronOne.BoardPACWinAppUtil.Util;
using GalaSoft.MvvmLight.Messaging;
using pdftron.FDF;
using pdftron.PDF;
using Image = pdftron.PDF.Image;
using com.IronOne.BoardPACWinAppService;
using com.IronOne.BoardPACWinAppService.Agenda;

namespace com.IronOne.BoardPACWinApp.Common
{
    public class BasePage
    {
        /// <summary>
        ///     3000
        /// </summary>
        private const int CheckDelay = 3000;

        private static ICommentService _commentService;
        private static BasePage _basePage;
        private readonly IAuthService _authService;
        private readonly IAgendaService _agendaService;
        private readonly IDialogService _dialogService;
        private readonly INavigationService _navigationService;

        private BasePage()
        {
            _navigationService = new NavigationService();
            _dialogService = new DialogService();
            _authService = new AuthService();
            _commentService = new CommentService();
            _agendaService = new AgendaService();
        }

        public static BasePage GetInstance()
        {
            return _basePage ?? (_basePage = new BasePage());
        }

        public async Task HandleMessages(NotificationMessage<MessageDataModel> mdm)
        {
            try
            {
                if (mdm.Notification.Equals(MessageCodes.WIPEOUT_NOTIFY_TO_UI))
                {
                    SyncManager.StopSync();
                    await _authService.WipeoutDevice();
                    await
                        CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPriority.Normal,
                            () =>
                            {
                                _navigationService.NavigateTo(typeof (WipedOutPage), mdm.Content.MessageData.ToString());
                            });
                }
                if (mdm.Notification.Equals(MessageCodes.SESSION_TIMEOUT_NOTIFY_TO_UI))
                {
                    await CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
                    {
                        _dialogService.ShowMessage(mdm.Content.MessageData.ToString());
                        _navigationService.NavigateTo(typeof(LoginPage), ErrorCode.Err110);
                    });
                }
                if (mdm.Notification.Equals(MessageCodes.DEVICE_DEACTIVATE_NOTIFY_TO_UI))
                {
                    await CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
                    {
                        _dialogService.ShowMessage(mdm.Content.MessageData.ToString());
                        _navigationService.NavigateTo(typeof (LoginPage));
                    });
                }
                if (mdm.Notification.Equals(MessageCodes.SYNC_ERROR_STOP))
                {
                    await CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
                    {
                        //bool result = await _dialogService.ShowMessageRestartCancel(mdm.Content.MessageData.ToString() + "\nDo you want to restart?", DefaultButtonCommand.Yes);
                        //if (result)
                        //SyncManager.GetInstance().StartSync();

                        _dialogService.ShowMessage(mdm.Content.MessageData.ToString());
                    });
                }
                if (mdm.Notification.Equals(MessageCodes.UPDATE_USER_APPROVAL_ERROR))
                {
                    await
                        CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPriority.Normal,
                            () => { _dialogService.ShowMessage(mdm.Content.MessageData.ToString()); });
                }
            }
            catch (Exception)
            {
            }
        }

        public static void PinnedAppBarButton_Checked(AppBarToggleButton pinnedAppBarButton, AppSettingsManager asm)
        {
            try
            {
                pinnedAppBarButton.Label = "UnPin";
                asm.SetAppBarPinnedStatus(true);

                var mdm = new MessageDataModel {MessageData = true};
                var message = new NotificationMessage<MessageDataModel>(mdm, MessageCodes.APPBAR_PIN);
                Messenger.Default.Send(message);
            }
            catch (Exception)
            {
            }
        }

        public static void PinnedAppBarButton_UnChecked(AppBarToggleButton pinnedAppBarButton, AppSettingsManager asm)
        {
            try
            {
                pinnedAppBarButton.Label = "Pin";
                asm.SetAppBarPinnedStatus(false);

                var mdm = new MessageDataModel {MessageData = false};
                var message = new NotificationMessage<MessageDataModel>(mdm, MessageCodes.APPBAR_PIN);
                Messenger.Default.Send(message);
            }
            catch (Exception)
            {
            }
        }

        public static void CommentButton_Click(INavigationService navigationService)
        {
            navigationService.NavigateTo(typeof (CommentsPage));
        }

        public static void MeetingsButton_Click(INavigationService navigationService)
        {
            navigationService.NavigateTo(typeof (MeetingsPage));
        }

        public static void PastPapersButton_Click(INavigationService navigationService)
        {
            navigationService.NavigateTo(typeof (PastPapersSearchPage));
        }

        public static async Task LogoutButton_Click(INavigationService navigationService, IDialogService dialogService,
            IAuthService authService)
        {
            await LogoutButtonCommon(navigationService, dialogService, authService, true);
        }

        private static async Task LogoutButtonCommon(INavigationService navigationService, IDialogService dialogService,
            IAuthService authService, bool isGotoLogin)
        {
            try
            {
                var result =
                    await dialogService.ShowMessageYesNo("Are you sure you want to logout?", DefaultButtonCommand.No);
                if (result)
                {
                    var count = await GetPendingComments();
                    if (count > 0 && Global.IsOnline && !Global.UserForceWentOffline)
                    {
                        //https://social.msdn.microsoft.com/forums/windowsapps/en-us/2c7b290a-dd84-44a7-b3f4-29abc55fe010/how-to-show-dialog-with-textbox-control
                        InputMessageDialog dlg;
                        if (count == 1)
                            dlg = new InputMessageDialog("There is a pending comment", Visibility.Collapsed,
                                Visibility.Collapsed, true);
                        else
                            dlg = new InputMessageDialog("There are " + count + " pending comments",
                                Visibility.Collapsed, Visibility.Collapsed, true);
                        dlg.ShowAsync();

                        while (count > 0)
                        {
                            await Task.Delay(CheckDelay);
                            count = await _commentService.GetPendingMeetingAndPaperComments();

                            if (count <= 0) break;
                        }
                        dlg.HideAsync();

                        dlg = new InputMessageDialog("Logging out", Visibility.Collapsed, Visibility.Collapsed, true);
                        dlg.ShowAsync();
                        await authService.Logout();
                        dlg.HideAsync();

                        LogoutCommon(navigationService, isGotoLogin);
                    }
                    else if (Global.IsOnline && !Global.UserForceWentOffline)
                    {
                        var dlg = new InputMessageDialog("Logging out", Visibility.Collapsed, Visibility.Collapsed, true);
                        dlg.ShowAsync();
                        await authService.Logout();
                        dlg.HideAsync();

                        LogoutCommon(navigationService, isGotoLogin);
                    }
                    else
                    {
                        LogoutCommon(navigationService, isGotoLogin);
                    }
                }
            }
            catch (Exception)
            {
            }
        }

        private static async Task<int> GetPendingComments()
        {
            var count = await _commentService.GetPendingMeetingAndPaperComments();
            return count;
        }

        private static void LogoutCommon(INavigationService navigationService, bool isGotoLogin)
        {
            Global.CleanUp();
            ViewModelLocator.Cleanup();
            if (isGotoLogin)
                navigationService.NavigateTo(typeof (LoginPage));
        }

        public static void CleanupPartial()
        {
            ViewModelLocator.CleanupPartial();
        }

        public static async Task<BitmapImage> UpdateProfilePic(int userId)
        {
            try
            {
                var profileFolder = await ApplicationData.Current.LocalFolder.GetFolderAsync("Profile");

                var img = await profileFolder.TryGetItemAsync(userId + ".png") as IStorageFile;
                var bitmapImage = new BitmapImage();

                if (img == null)
                    img =
                        await
                            StorageFile.GetFileFromApplicationUriAsync(
                                new Uri("ms-appx:///Assets/Images/Common/DefaultProfilePic.png"));

                using (var stream = await img.OpenReadAsync())
                {
                    bitmapImage.SetSource(stream);
                }
                return bitmapImage;
            }
            catch (Exception)
            {
            }

            return null;
        }

        internal string GetDocTypeName(byte? doctype)
        {
            try
            {
                var val = (int) doctype;

                switch (val)
                {
                    case (int) DocumentType.AudioVideo:
                        return "Media item is ";

                    case (int) DocumentType.BoardPaper:
                        return "Board paper is ";

                    case (int) DocumentType.DiscussionItem:
                        return "Discussion item is ";

                    case (int) DocumentType.DiscussionPaper:
                        return "Discussion paper is ";

                    case (int) DocumentType.InformationPaper:
                        return "Information paper is ";

                    case (int) DocumentType.SupportDocument:
                        return "Support document is ";

                    case (int) PaperTypes.SharedDoc:
                        return "Shared document is ";

                    case (int) PaperTypes.NewsItem:
                        return "News item is ";

                    default:
                        return "";
                }
            }
            catch (Exception)
            {
                throw;
            }
        }

        internal void GotoButton_Click(PDFViewCtrl pDfViewCtrl, TextBox gotoTextBox)
        {
            pDfViewCtrl.SetCurrentPage(Int32.Parse(gotoTextBox.Text.Trim()));
        }

        internal void GotoTextBox_TextChanged(TextBox gotoTextBox, Button gotoButton, PDFViewCtrl pDfViewCtrl)
        {
            try
            {
                var gotoValue = gotoTextBox.Text.Trim();

                gotoTextBox.BorderBrush = new SolidColorBrush(Colors.Gray);
                gotoButton.Foreground = new SolidColorBrush(Colors.LightGray);
                gotoButton.IsEnabled = false;

                if (String.IsNullOrWhiteSpace(gotoValue)) return;

                int result;
                var pass = Int32.TryParse(gotoValue, out result);
                if (pass && result > 0 && result <= pDfViewCtrl.GetPageCount())
                {
                    gotoButton.IsEnabled = true;
                    gotoButton.Foreground = new SolidColorBrush(Colors.White);
                }
                else
                {
                    gotoTextBox.BorderBrush = new SolidColorBrush(Colors.Red);
                    gotoButton.Foreground = new SolidColorBrush(Colors.LightGray);
                    gotoButton.IsEnabled = false;
                }
            }
            catch (Exception)
            {
                gotoTextBox.BorderBrush = new SolidColorBrush(Colors.Gray);
                gotoButton.Foreground = new SolidColorBrush(Colors.LightGray);
                gotoButton.IsEnabled = false;
            }
        }

        #region Annotation File Operations

        public static string oldAnnotationString = "";

        public async Task ExportAnnotations(PDFDoc doc, AgendaItem globalSelectdAgendaItem, int currentPage)
        {
            try
            {
                if (doc != null && globalSelectdAgendaItem != null)
                {
                    var documentsFolder = await Utility.GetShareOriginalFolder();
                    var annotationFileName = globalSelectdAgendaItem.Id + "_" + Global.UserId + "_" +
                                             globalSelectdAgendaItem.VersionId + ApplicationConstants.ANNOTATEEXT;

                    doc.InitSecurityHandler();
                    // Extract the annotations
                    var docAnnots = doc.FDFExtract(PDFDocExtractFlag.e_annots_only);
                    string annotString = "";

                    if (docAnnots != null)
                    {
                        annotString = docAnnots.SaveAsXFDFString();
                        if (oldAnnotationString.Equals(annotString)) return;
                        oldAnnotationString = annotString; 
                    }

                    bool isAnnotAvailable = (docAnnots != null && annotString.ToLower().Contains("<annots>"));

                    var anntotationFile = await GetAnnotationFile(globalSelectdAgendaItem);
                    if (anntotationFile != null)
                    {
                        await anntotationFile.DeleteAsync(StorageDeleteOption.PermanentDelete);
                        if (!isAnnotAvailable)
                            await _agendaService.UpdateIsAnnotBackupNeededOnVersionTable(globalSelectdAgendaItem.Id, globalSelectdAgendaItem.VersionId, currentPage, false);
                    }
                    
                    // Export the annotations in XFDF format only if it contains annotations
                    if (isAnnotAvailable)
                    {
                        await docAnnots.SaveAsXFDFAsync(Path.Combine(documentsFolder.Path, annotationFileName));
                        await _agendaService.UpdateIsAnnotBackupNeededOnVersionTable(globalSelectdAgendaItem.Id, globalSelectdAgendaItem.VersionId, currentPage, true);
                    }
                }
            }
            catch (Exception)
            {
                throw;
            }
        }

        public async Task<PDFDoc> ImportAnnotations(PDFDoc doc, AgendaItem globalSelectdAgendaItem)
        {
            try
            {
                if (doc == null || globalSelectdAgendaItem == null) return doc;

                var documentsFolder = await Utility.GetShareOriginalFolder();
                var annotationFileName = globalSelectdAgendaItem.Id + "_" + Global.UserId + "_" +
                                         globalSelectdAgendaItem.VersionId + ApplicationConstants.ANNOTATEEXT;

                // load XFDF annotations
                FDFDoc fdfDoc;
                var anntotationFile = await GetAnnotationFile(globalSelectdAgendaItem);
                if (anntotationFile != null)
                    fdfDoc = await FDFDoc.CreateFromXFDFAsync(Path.Combine(documentsFolder.Path, annotationFileName));
                else
                    return doc;

                // load PDF with which to merge the annotations
                doc.InitSecurityHandler();

                // merge in the annotations
                doc.FDFMerge(fdfDoc);
                doc.RefreshFieldAppearances();
                return doc;
            }
            catch (Exception)
            {
                throw;
            }
        }

        public async Task<PDFDoc> ImportSharedAnnotations(PDFDoc doc, PaperModel pModel, ShareType type)
        {
            try
            {
                if (doc == null || pModel == null) return doc;

                StorageFolder shareFolder = null;
                if (type == ShareType.Sent) shareFolder = await Utility.GetShareSentFolder();
                if (type == ShareType.Received) shareFolder = await Utility.GetShareReceivedFolder();

                // load XFDF annotations
                FDFDoc fdfDoc;
                //Load XFDF annotations

                var documentname = "";
                if (type == ShareType.Sent)
                {
                    documentname = pModel.DocName;
                }
                if (type == ShareType.Received)
                {
                    documentname = pModel.PaperId + "_" + Global.UserId + "_" + pModel.VersionId + "_" +
                                   pModel.AsAnnotationShareId + ApplicationConstants.ANNOTATEEXT;
                }

                var anntotationFile = await shareFolder.TryGetItemAsync(documentname);
                if (anntotationFile != null)
                    fdfDoc = await FDFDoc.CreateFromXFDFAsync(Path.Combine(shareFolder.Path, documentname));
                else
                    return null;

                // load PDF with which to merge the annotations
                doc.InitSecurityHandler();

                // merge in the annotations
                doc.FDFMerge(fdfDoc);
                doc.RefreshFieldAppearances();
                return doc;
            }
            catch (Exception)
            {
                return null;
            }
        }

        public static async Task<IStorageItem> GetAnnotationFile(AgendaItem globalSelectdAgendaItem)
        {
            try
            {
                var documentsFolder = await Utility.GetShareOriginalFolder();
                var annotationFileName = globalSelectdAgendaItem.Id + "_" + Global.UserId + "_" +
                                         globalSelectdAgendaItem.VersionId + ApplicationConstants.ANNOTATEEXT;

                //Load XFDF annotations
                var anntotationFile = await documentsFolder.TryGetItemAsync(annotationFileName);
                return anntotationFile;
            }
            catch (Exception)
            {
                return null;
            }
        }


        public async Task<PDFDoc> SetApprovalStamp(PDFDoc pdfDoc, PDFViewCtrl pdfViewCtrl, string paperStatus,
            AgendaItem globalSelectdAgendaItem)
        {
            try
            {
                Uri uri = null;
                Stamper.DeleteStamps(pdfDoc, new PageSet(1));

                //pdftron.PDF.Image stampImg = null;
                //PDFDoc doc = ClearStamp(pdfDoc); //this.PDFViewCtrl.GetDoc();
                //pdftron.PDF.Page first_page = doc.GetPage(1);

                const string path = "ms-appx:///Assets/Images/AgendaPage/Stamp/";

                if (paperStatus.Equals(DecisionStatus.Approve.ToString()) ||
                    paperStatus.Equals(PaperStatus.Approved.ToString()))
                {
                    uri = new Uri(path + "Agenda_Stamp_Approve.png");
                }
                else if (paperStatus.Equals(DecisionStatus.Abstain.ToString()))
                {
                    uri = new Uri(path + "Agenda_Stamp_Abstain.png");
                }
                else if (paperStatus.Equals(DecisionStatus.Interest.ToString()))
                {
                    uri = new Uri(path + "Agenda_Stamp_Interest.png");
                }
                else if (paperStatus.Equals(DecisionStatus.Reject.ToString()) ||
                         paperStatus.Equals(PaperStatus.Rejected.ToString()))
                {
                    uri = new Uri(path + "Agenda_Stamp_Rejected.png");
                }
                else if (paperStatus.Equals(DecisionStatus.Rpt.ToString()))
                {
                    uri = new Uri(path + "Agenda_Stamp_RPT.png");
                }
                else if (paperStatus.Replace(" ", string.Empty).Equals(PaperStatus.CarriedForward.ToString()))
                {
                    uri = new Uri(path + "Agenda_Stamp_Carried Forward.png");
                }

                if (uri != null)
                {
                    var sf = await StorageFile.GetFileFromApplicationUriAsync(uri);

                    //StorageFile sf = stampImageFile.GetResults();
                    var s = await sf.OpenStreamForReadAsync();
                    byte[] arr;
                    using (var ms = new MemoryStream())
                    {
                        s.CopyTo(ms);
                        arr = ms.ToArray();
                    }

                    #region EmbedImage

                    //----------Old method--------------------------
                    //using (ElementBuilder bld = new ElementBuilder())   // Used to build new Element objects
                    //using (ElementWriter writer = new ElementWriter())  // Used to write Elements to the page   
                    //{
                    //    writer.Begin(first_page);

                    //    Element element = bld.CreateImage(stampImg, new Matrix2D(stampImg.GetImageWidth(), 0, 0, stampImg.GetImageHeight(), 225, 500));  //x  y 

                    //    writer.WritePlacedElement(element);

                    //    writer.End();   // Finish writing to the page
                    //    doc.PagePushBack(first_page);
                    //}
                    //---------------------------------------------

                    using (var st = new Stamper(StamperSizeType.e_relative_scale, 0.30, 0.30))
                    {
                        pdfDoc.InitSecurityHandler();

                        var img = Image.Create(pdfDoc.GetSDFDoc(), arr);
                        st.SetSize(StamperSizeType.e_relative_scale, 0.30, 0.30);
                        //set position of the image to the center, left of PDF pages
                        st.SetAlignment(StamperHorizontalAlignment.e_horizontal_center,
                            StamperVerticalAlignment.e_vertical_top);
                        //st.SetFontColor(new ColorPt(0, 0, 0, 0));
                        //st.SetRotation(180);
                        st.SetAsBackground(false);
                        st.ShowsOnScreen(true);
                        //only stamp first page
                        st.StampImage(pdfDoc, img, new PageSet(1));
                    }

                    #endregion
                }
            }
            catch (Exception)
            {
                throw;
            }
            return pdfDoc;
        }

        /*private PDFDoc ClearStamp(PDFDoc doc)
        {
            try
            {
                ElementWriter writer = new ElementWriter();
                ElementReader reader = new ElementReader();

                Page page = doc.GetPage(1);
                reader.Begin(page);
                writer.Begin(page, ElementWriterWriteMode.e_replacement, false);
                Element element;
                while ((element = reader.Next()) != null) // Read page contents
                {
                    switch (element.GetType())
                    {
                        case ElementType.e_image:
                            break;
                        case ElementType.e_inline_image:
                            break;
                        default:
                            writer.WriteElement(element);
                            break;
                    }
                }
                writer.End();
                reader.End();
            }
            catch (Exception)
            {
            }
            return doc;
        }*/

        #endregion

        internal async Task<int> GetCurrentPageOfThePaper(int paperId, int versionId)
        {
            try
            {
                int pageNo = await _agendaService.GetCurrentPageOfThePaper(paperId, versionId);
                return (pageNo <= 0) ? 1 : pageNo;
            }
            catch (Exception)
            {
                return 1;
            }
        }
    }
}